﻿// Copyright (c) 2013, Simon Carter.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted 
// provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of 
//   conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this list of 
//  conditions and the following disclaimer in the documentation and/or other materials provided 
//  with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// History
// Initial Release - Simon Carter
//

using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace ErrorManager.Server.DAL
{
    public class XML : BaseEngine
    {
        private EngineLoggingLevel _logLevel;

        #region Initialisation

        /// <summary>
        /// Initialisation method
        /// </summary>
        /// <param name="logLevel">Logging Level (Normal or Debug)</param>
        /// <param name="connectionString">Connection String used by DAL (if required)</param>
        public override void Initialise(EngineLoggingLevel logLevel, string connectionString)
        {
            _logLevel = logLevel;
        }

        /// <summary>
        /// Initialised Method
        /// 
        /// Called after the DAL has been initialised
        /// </summary>
        public override void Initialised()
        {
            //do nothing, not required with XML DAL
        }

        #endregion Initialisation

        #region Service Settings

        /// <summary>
        /// Specify the IP Address the Server is bound to
        /// 
        /// Not currently implemented
        /// </summary>
        /// <returns>IP Address</returns>
        public override string BindIPAddress()
        {
            return ("*");
        }

        /// <summary>
        /// Specifiy the port the server is bound to
        /// </summary>
        /// <returns>Port Number</returns>
        public override int BindIPPort()
        {
            return (Convert.ToInt32(GetXMLValue("Service", "Port")));
        }

        #endregion Service Settings

        #region User Editable Server Configuration

        /// <summary>
        /// Returns the currently configured Port for the server
        /// </summary>
        /// <param name="userName">Name of user making request</param>
        /// <returns>port number if user has permission, otherwise 0 (zero)</returns>
        public override int ServerConfigGetPort(string userName)
        {
            int Result = 0;

            if (UserHasPermission(userName, UserSecurityPermissions.ConfigureServer))
            {
                XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

                var result = xdoc.Root.Element("Service").Elements("Port").SingleOrDefault().Value;
                Result = Convert.ToInt32(result);
            }

            return (Result);
        }

        /// <summary>
        /// Sets the port number used by the service
        /// </summary>
        /// <param name="userName">Name of user making request</param>
        /// <param name="port">New port number</param>
        /// <returns>void</returns>
        public override void ServerConfigSetPort(string userName, int port)
        {
            throw new NotImplementedException();
        }


        /// <summary>
        /// Returns the currently configured DAL for the server
        /// </summary>
        /// <param name="userName">Name of user making request</param>
        /// <returns>DAL name if user has permissions, otherwise blank string</returns>
        public override string ServerConfigGetDAL(string userName)
        {
            string Result = String.Empty;

            if (UserHasPermission(userName, UserSecurityPermissions.ConfigureServer))
            {
                XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

                var result = xdoc.Root.Element("Service").Elements("DataAccessLayer").SingleOrDefault().Value;
                Result = result;
            }

            return (Result);
        }

        /// <summary>
        /// Set's the active Data Access Layer (DAL)
        /// </summary>
        /// <param name="userName">Name of user making the request</param>
        /// <param name="dataAccessLayer">New DAL Class Name</param>
        public override void ServerConfigSetDAL(string userName, string dataAccessLayer)
        {
            throw new NotImplementedException();
        }


        #endregion User Editable Server Configuration

        #region Client Options

        /// <summary>
        /// Client Login
        /// </summary>
        /// <param name="userName">Username of client logging in</param>
        /// <param name="password">Password for client logging in</param>
        /// <returns>bool, true if client successfully logged in, otherwise false</returns>
        public override bool ClientLogin(string userName, string password)
        {
            try
            {
                XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

                var result = (from e in xdoc.Descendants("Users").Elements()
                              where (string)e.Element("Username") == userName
                              select e).Descendants("Password").First().Value;

#if !DEBUG
                SetUserValue(userName, "LastLoginAttempt", DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"));
#endif

                return (result == password);
            }
            catch (Exception err)
            {
                if (_logLevel == EngineLoggingLevel.Debug)
                    EngineHelper.AddToLog(String.Format("Error: {0}", err.Message));

                return (false);
            }
        }

        /// <summary>
        /// Determines whether a client can login from a specific IP Address
        /// </summary>
        /// <param name="ipAddress">IP Address for client</param>
        /// <returns>true if client can login from the IP Address, otherwise false</returns>
        public override bool ClientAllowConnect(string ipAddress)
        {
            if (GetXMLValue("ClientIP", "AllowAll") == "true")
            {
                return (true);
            }
            else
            {
                return (GetXMLValue("ClientIP", String.Format("Client_{0}", ipAddress.Replace(".", "_"))) == "true");
            }
        }

        /// <summary>
        /// Retrieves the last error id
        /// </summary>
        /// <param name="userName">Name of user logging an error</param>
        /// <returns>Unique uint containing the last error ID</returns>
        public override uint ClientErrorReportCount(string userName)
        {
            uint Result = 0;

            try
            {
                XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

                var result = (from e in xdoc.Descendants("Users").Elements()
                              where (string)e.Element("Username") == userName
                              select e).Descendants("NextError").First().Value;

                Result = Convert.ToUInt32(result);

                return (Result);
            }
            catch (Exception err)
            {
                if (_logLevel == EngineLoggingLevel.Debug)
                    EngineHelper.AddToLog(String.Format("Error - ClientErrorUniqueID: {0}", err.Message));

                return (Result);
            }
        }

        /// <summary>
        /// Returns the next unique client error number
        /// </summary>
        /// <param name="userName">Username of client</param>
        /// <returns>Int64, unique ID for error number</returns>
        public override Int64 ClientErrorUniqueID(string userName)
        {
            Int64 Result = 0;

            try
            {
                XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

                var result = (from e in xdoc.Descendants("Users").Elements()
                              where (string)e.Element("Username") == userName
                              select e).Descendants("NextError").First().Value;

                Result = Convert.ToInt64(result);

                //Save the next error number
                SetUserValue(userName, "NextError", Result + 1);

                return (Result);
            }
            catch (Exception err)
            {
                if (_logLevel == EngineLoggingLevel.Debug)
                    EngineHelper.AddToLog(String.Format("Error - ClientErrorUniqueID: {0}", err.Message));

                return (Result);
            }
        }

        /// <summary>
        /// Returns a list of error numbers held on file
        /// 
        /// List is seperated by $
        /// </summary>
        /// <param name="userName">User making the request</param>
        /// <returns>string of error numbers</returns>
        public override string ClientErrorsGet(string userName)
        {
            string Result = String.Empty;

            string[] files = Directory.GetFiles(String.Format("{0}\\{1}\\", EngineHelper.Path, userName), "*.dat");
            string ignoreList = UserErrorGetIgnoreList(userName);
            
            foreach (string s in files)
            {
                if (!s.Contains("extra"))
                    if (!ignoreList.Contains(String.Format(",{0},", Path.GetFileName(s).Replace(".dat", String.Empty))))
                        Result += System.IO.Path.GetFileName(s).Replace(".dat", String.Empty) + "$";
            }

            return (Result);
        }

        /// <summary>
        /// Returns Error information if available
        /// </summary>
        /// <param name="currentUser">User making the request</param>
        /// <param name="error">Error Number</param>
        /// <returns>Returns the error information</returns>
        public override string UserGetErrorInformation(string userName, uint error)
        {
            string Result = String.Empty;

            string file = String.Format("{0}\\{1}\\{2}.dat", EngineHelper.Path, userName, error);

            if (File.Exists(file))
            {
                using (StreamReader sr = new StreamReader(file))
                {
                    Result = sr.ReadToEnd();
                }
            }

            return (Result);
        }

        /// <summary>
        /// Returns Extra Error information if available
        /// </summary>
        /// <param name="currentUser">User making the request</param>
        /// <param name="error">Error Number</param>
        /// <returns>Returns the extra error information</returns>
        public override string UserGetErrorExtraInformation(string userName, uint error)
        {
            string Result = String.Empty;

            string file = String.Format("{0}\\{1}\\{2}.extra.dat", EngineHelper.Path, userName, error);

            if (File.Exists(file))
            {
                using (StreamReader sr = new StreamReader(file))
                {
                    Result = sr.ReadToEnd();
                }
            }

            return (Result);
        }

        /// <summary>
        /// Determines whether an error also has an image
        /// </summary>
        /// <param name="userName">User making the request</param>
        /// <param name="error">Error Number</param>
        /// <returns>true if an image exists, otherwise false</returns>
        public override bool UserGetErrorHasImage(string userName, uint error)
        {
            bool Result = false;

            string file = String.Format("{0}\\{1}\\", EngineHelper.Path, userName);
            string[] files = Directory.GetFiles(file, String.Format("{0}_*.gif", error));

            Result = files.Count() > 0;

            return (Result);
        }

        /// <summary>
        /// Returns a file name to the error string
        /// </summary>
        /// <param name="userName">User making the request</param>
        /// <param name="error">Error Number</param>
        /// <returns>File name of error image</returns>
        public override string UserGetErrorImage(string userName, uint error)
        {
            string Result = String.Empty;

            string file = String.Format("{0}\\{1}\\", EngineHelper.Path, userName);
            string[] files = Directory.GetFiles(file, String.Format("{0}_*.gif", error));

            if (files.Count() > 0)
                Result = Path.GetFileName(files[0]);

            return (Result);
        }

        /// <summary>
        /// Deletes an error from the system
        /// </summary>
        /// <param name="userName">User making the request</param>
        /// <param name="error">Error Number</param>
        public override void UserErrorDelete(string userName, uint error)
        {
            string file = String.Format("{0}\\{1}\\", EngineHelper.Path, userName);

            DeleteFile(String.Format("{0}{1}.dat", file, error));
            DeleteFile(String.Format("{0}{1}.extra.dat", file, error));
            DeleteFile(UserGetErrorImage(userName, error));

            string[] files = Directory.GetFiles(file, String.Format("{0}_*.*", error));

            foreach (string s in files)
            {
                DeleteFile(s);
            }
        }

        /// <summary>
        /// Returns a comma seperated list of all ignored errors
        /// </summary>
        /// <param name="userName">User making the request</param>
        /// <param name="defaultValue">default value to return if empty/not found</param>
        /// <returns>Comma seperated string list of errors to ignore</returns>
        public override string UserErrorGetIgnoreList(string userName, string defaultValue = ",")
        {
            string Result = defaultValue;

            try
            {
                XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

                var result = (from e in xdoc.Descendants("Users").Elements()
                              where (string)e.Element("Username") == userName
                              select e).Descendants("IgnoreList").First().Value;

                Result = result;

                if (String.IsNullOrEmpty(Result))
                    Result = defaultValue;

                return (Result);
            }
            catch 
            {
                return (defaultValue);
            }
        }

        /// <summary>
        /// Ignore's an error from the list, hides it from user view
        /// </summary>
        /// <param name="userName">User making the request</param>
        /// <param name="error">Error Number</param>
        public override void UserErrorIgnore(string userName, uint error)
        {
            string ignoreList = UserErrorGetIgnoreList(userName);

            ignoreList += String.Format("{0},", error);

            SetUserValue(userName, "IgnoreList", ignoreList);
        }

        #endregion Client Options

        #region User Management

        /// <summary>
        /// Determines wether a user has a specific permission
        /// </summary>
        /// <param name="currentUser">User</param>
        /// <param name="permission">Permission being sought</param>
        /// <returns></returns>
        public override bool UserHasPermission(string currentUser, UserSecurityPermissions permission)
        {
            try
            {
                XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

                var result = (from e in xdoc.Descendants("Users").Elements()
                              where (string)e.Element("Username") == currentUser
                              select e).Descendants("Permissions").First().Value;
                
                UserSecurityPermissions userPermissions = (UserSecurityPermissions)Convert.ToInt64(result);
                return ((userPermissions & permission) == permission);
            }
            catch (Exception err)
            {
                if (_logLevel == EngineLoggingLevel.Debug)
                    EngineHelper.AddToLog(String.Format("Error: {0}", err.Message));

                return (false);
            }
        }

        /// <summary>
        /// Returns a list of users within the system
        /// </summary>
        /// <param name="currentUser">User making the request</param>
        /// <returns>List of user names seperated by \r (line feed)</returns>
        public override string UsersGet(string currentUser)
        {
            string Result = String.Empty;

            //check user permissions
            if (!UserHasPermission(currentUser, UserSecurityPermissions.ManageSystemUsers))
                return (Result);

            XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

            //Run query
            var result = from e in xdoc.Descendants("Users").Elements()
                 select (string)e.Element("Username");

            //Loop through results
            foreach (string user in result)
            {
                Result += String.Format("{0}\r", user);
            }

            return (Result);
        }

        /// <summary>
        /// Creates a new user on the system
        /// </summary>
        /// <param name="userName">Name of new user</param>
        public override bool UserCreate(string currentUser, string userName)
        {
            //check user permissions
            if (!UserHasPermission(currentUser, UserSecurityPermissions.ManageSystemUsers))
                return (false);

            SetUserValue(userName, "Active", "False");
            Directory.CreateDirectory(String.Format("{0}\\{1}", EngineHelper.Path, userName));

            return (true);
        }

        /// <summary>
        /// Set's the password for a user
        /// </summary>
        /// <param name="currentUser">User making the request</param>
        /// <param name="userName">User who's password is to be changed</param>
        /// <param name="password">New password for user</param>
        public override bool UserSetPassword(string currentUser, string userName, string password)
        {
            //check user permissions
            if (!UserHasPermission(currentUser, UserSecurityPermissions.ManageSystemUsers))
                return (false);

            SetUserValue(userName, "Password", password);

            return (true);
        }

        /// <summary>
        /// Set the Permissions for a user
        /// </summary>
        /// <param name="currentUser">User making the request</param>
        /// <param name="userName">User who's Permission level will be changed</param>
        /// <param name="permissions">Permissions to assign to use</param>
        public override bool UserSetPermissions(string currentUser, string userName, UserSecurityPermissions permissions)
        {
            //check user permissions
            if (!UserHasPermission(currentUser, UserSecurityPermissions.ManageSystemUsers))
                return (false);

            SetUserValue(userName, "Permissions", ((int)permissions).ToString());

            return (true);
        }

        /// <summary>
        /// Delete's a user
        /// </summary>
        /// <param name="currentUser">User making the request</param>
        /// <param name="userName">User to be deleted</param>
        /// <returns>true if user deleted and all files removed, otherwise false</returns>
        public override bool UserDelete(string currentUser, string userName)
        {
            //check user permissions
            if (!UserHasPermission(currentUser, UserSecurityPermissions.ManageSystemUsers))
                return (false);

            XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

            var result = (from e in xdoc.Descendants("Users").Elements()
                          where (string)e.Element("Username") == userName
                          select e);

            result.Remove();

            //delete all user files
            string dir = String.Format("{0}\\{1}", EngineHelper.Path, userName);
            string[] files = Directory.GetFiles(dir);

            foreach (string file in files)
                DeleteFile(file);

            Directory.Delete(dir);

            //save the changes
            xdoc.Save(EngineHelper.Path + "\\ErrorManager.Config.xml");

            return (true);
        }

        /// <summary>
        /// Changes active state of user
        /// </summary>
        /// <param name="currentUser">User making the request</param>
        /// <param name="userName">User who's active state is to be changed</param>
        /// <param name="active">bool, true if user is active (able to login etc) or false (unable to use system)</param>
        public override bool UserSetActive(string currentUser, string userName, bool active)
        {
            //check user permissions
            if (!UserHasPermission(currentUser, UserSecurityPermissions.ManageSystemUsers))
                return (false);

            SetUserValue(userName, "Active", active.ToString());

            return (true);
        }

        /// <summary>
        /// Gets a value indicating wether the user is active
        /// </summary>
        /// <param name="currentUser">User making the request</param>
        /// <param name="userName">User who's active state is to be changed</param>
        /// <returns>true if active, otherwise false</returns>
        public override bool UserGetActive(string currentUser, string userName)
        {
            //check user permissions
            if (!UserHasPermission(currentUser, UserSecurityPermissions.ManageSystemUsers))
                return (false);

            XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

            var result = (from e in xdoc.Descendants("Users").Elements()
                          where (string)e.Element("Username") == userName
                          select e).Descendants("Active").First().Value;

            return (Convert.ToBoolean(result));
        }

        /// <summary>
        /// Get's a users password
        /// </summary>
        /// <param name="currentUser">User making the request</param>
        /// <param name="userName">User who's active state is to be changed</param>
        /// <returns>Password for user</returns>
        public override string UserGetPassword(string currentUser, string userName)
        {
            //check user permissions
            if (!UserHasPermission(currentUser, UserSecurityPermissions.ManageSystemUsers))
                return (String.Empty);

            XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

            var result = (from e in xdoc.Descendants("Users").Elements()
                          where (string)e.Element("Username") == userName
                          select e).Descendants("Password").First().Value;

            return (result);
        }

        /// <summary>
        /// Retrieves the last login date/time for a user
        /// </summary>
        /// <param name="currentUser">User making the request</param>
        /// <param name="userName">User who's active state is to be changed</param>
        /// <returns>Last Login Date/Time</returns>
        public override string UserGetLastLogin(string currentUser, string userName)
        {
            //check user permissions
            if (!UserHasPermission(currentUser, UserSecurityPermissions.ManageSystemUsers))
                return (String.Empty);

            try
            {
                XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

                var result = (from e in xdoc.Descendants("Users").Elements()
                              where (string)e.Element("Username") == userName
                              select e).Descendants("LastLoginAttempt").First().Value;

                return (result);
            }
            catch
            {
                return (DateTime.Now.AddYears(-10).ToString("dd/MM/yyyy HH:mm"));
            }
        }

        /// <summary>
        /// Retrieves the permissions for a user
        /// </summary>
        /// <param name="currentUser">User making the request</param>
        /// <param name="userName">User who's active state is to be changed</param>
        /// <returns>List of permissions</returns>
        public override string UserGetPermissions(string currentUser, string userName)
        {
            //check user permissions
            if (!UserHasPermission(currentUser, UserSecurityPermissions.ManageSystemUsers))
                return (String.Empty);

            XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

            var result = (from e in xdoc.Descendants("Users").Elements()
                          where (string)e.Element("Username") == userName
                          select e).Descendants("Permissions").First().Value;

            string Result = String.Empty;

            UserSecurityPermissions userPermissions = (UserSecurityPermissions)Convert.ToInt64(result);

            if ((userPermissions & UserSecurityPermissions.ConfigureServer) == UserSecurityPermissions.ConfigureServer)
                Result += String.Format("{0}\r\n", UserSecurityPermissions.ConfigureServer.ToString());

            if ((userPermissions & UserSecurityPermissions.ManageSystemUsers) == UserSecurityPermissions.ManageSystemUsers)
                Result += String.Format("{0}\r\n", UserSecurityPermissions.ManageSystemUsers.ToString());

            return (Result);
        }

        #endregion User Management

        #region Private Methods

        /// <summary>
        /// Delete's a file
        /// </summary>
        /// <param name="fileName">File to be deleted</param>
        private void DeleteFile(string fileName)
        {
            if (_logLevel == EngineLoggingLevel.Debug)
                EngineHelper.AddToLog(String.Format("Delete File: {0}", fileName));

            try
            {
                if (File.Exists(fileName))
                    File.Delete(fileName);
            }
            catch (Exception err)
            {
                if (_logLevel == EngineLoggingLevel.Debug)
                    EngineHelper.AddToLog(String.Format("Delete File Error: {0}", err.Message));
            }
        }

        #endregion Private Methods

        #region Static XML Read/Write Methods

        /// <summary>
        /// Updates a user property value
        /// </summary>
        /// <param name="userName">Name of user</param>
        /// <param name="property">Property to be updated</param>
        /// <param name="value">New Value of property</param>
        internal static void SetUserValue(string userName, string property, object value)
        {
            XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

            try
            {
                xdoc.Descendants("User")
                    .Where(x => x.Element("Username").Value == userName)
                    .Single().SetElementValue(property, value);
            }
            catch (Exception err)
            {
                if (err.Message.Contains("Sequence contains no elements"))
                {
                    //if not found...

                    XElement userRoot = xdoc.Root.Element("Users");
                    
                    userRoot.Add(new XElement("User", new XElement("Username", userName), new XElement(property, value)));
                }
                else
                    throw;
            }

            xdoc.Save(EngineHelper.Path + "\\ErrorManager.Config.xml");
        }

        /// <summary>
        /// Retrieves an XML Value
        /// </summary>
        /// <param name="ParentName"></param>
        /// <param name="KeyName"></param>
        /// <returns></returns>
        internal static string GetXMLValue(string ParentName, string KeyName)
        {
            XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

            var Result = xdoc.Root.Element(ParentName).Elements(KeyName).SingleOrDefault().Value;
            return (Result);
        }

        /// <summary>
        /// old old code do not use - TO BE REPLACED
        /// </summary>
        /// <param name="ParentName">Name of Parent Node</param>
        /// <param name="KeyName">Key Name</param>
        /// <param name="Value"></param>
        internal static void SetXMLValue(string ParentName, string KeyName, string Value)
        {
            string ConfigFile = EngineHelper.Path + "\\ErrorManager.Config.xml";
            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(ConfigFile);
            XmlNode Root = xmldoc.DocumentElement;
            bool FoundParent = false;
            bool Found = false;
            XmlNode xmlParentNode = null;

            if (Root != null & Root.Name == "ErrorServer")
            {
                for (int i = 0; i <= Root.ChildNodes.Count - 1; i++)
                {
                    XmlNode Child = Root.ChildNodes[i];

                    if (Child.Name == ParentName)
                    {
                        FoundParent = true;
                        xmlParentNode = Child;

                        for (int j = 0; j <= Child.ChildNodes.Count - 1; j++)
                        {
                            XmlNode Item = Child.ChildNodes[j];

                            if (Item.Name == KeyName)
                            {
                                Item.InnerText = Value;
                                Found = true;
                                xmldoc.Save(ConfigFile);
                            }
                        }
                    }
                }
            }

            if (!Found)
            {
                if (!FoundParent)
                {
                    xmlParentNode = xmldoc.CreateNode(XmlNodeType.Element, "", ParentName, null);
                    //XmlElement appendedParentName = xmldoc.CreateElement(ParentName);
                    Root.AppendChild(xmlParentNode);
                }

                XmlElement appendedKeyName = xmldoc.CreateElement(KeyName);
                XmlText xmlKeyName = xmldoc.CreateTextNode(Value);
                appendedKeyName.AppendChild(xmlKeyName);
                xmlParentNode.AppendChild(appendedKeyName);
                xmldoc.Save(ConfigFile);
            }
        }

        /// <summary>
        /// Retrieves an XML Value
        /// </summary>
        /// <param name="root">Name of Parent Node</param>
        /// <param name="searchTerm">Key Name</param>
        /// <param name="defaultValue">Default value if not found</param>
        /// <returns></returns>
        internal static string GetXMLValue(string root, string searchTerm, string defaultValue = "")
        {
            string Result = String.Empty;

            //Load xml
            XDocument xdoc = XDocument.Load(EngineHelper.Path + "\\ErrorManager.Config.xml");

            //Run query
            var lv1s = from lv1 in xdoc.Descendants(root)
                       select new
                       {
                           Header = lv1.Elements(searchTerm).ToString(),
                           Children = lv1.Descendants(searchTerm)
                       };

            //Loop through results
            foreach (var lv1 in lv1s)
            {
                foreach (var lv2 in lv1.Children)
                    Result = lv2.Value;
            }

            return (String.IsNullOrEmpty(Result) ? defaultValue : Result);
        }

        #endregion Static XML Read/Write Methods
    }
}
